package com.compomics.pridexmltomgfconverter.tools;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.util.List;
import java.util.logging.Level;
import org.apache.log4j.Logger;
import uk.ac.ebi.pride.jaxb.model.Contact;
import uk.ac.ebi.pride.jaxb.model.CvParam;
import uk.ac.ebi.pride.jaxb.model.Param;
import uk.ac.ebi.pride.jaxb.model.ProtocolSteps;
import uk.ac.ebi.pride.jaxb.model.Reference;
import uk.ac.ebi.pride.jaxb.xml.PrideXmlReader;

/**
 * Hello world!
 *
 */
public class MultipleOmicsPrideXMLParamExtractor {

    /**
     * Logger (includes file appender to log errors)
     */
    private static Logger logger = Logger.getLogger(MultipleOmicsPrideXMLParamExtractor.class);
    /**
     * Temporary file
     */
    private static File tempFile;
    /**
     * The maximum precursor charge detected in the PRIDE XML files.
     */
    private int maxPrecursorCharge = 4;
    /**
     * The minmim precursor charge detected in the PRIDE XML files.
     */
    private int minPrecursorCharge = 1;
    /**
     * Instance of the unzipper class
     */
    private GunZipper gunZipper;
    /**
     * Source File (prideXML)
     */
    private File prideXMLUnzipped;
    /**
     * Extractor for the data from the PRIDEXML file
     */
    private PrideXmlReader reader;
    /**
     * private Converter --> singleton reasons (MGF)
     */
    private static MultipleOmicsPrideXMLParamExtractor converter;
    /**
     * private exceptionhandler --> easier to get the errorlist from the
     * conversion
     */
    //  private static ConversionExceptionHandler errorHandler;
    private boolean zipped;
    private PrintWriter out;

    private MultipleOmicsPrideXMLParamExtractor() {
        gunZipper = GunZipper.getInstance();
    }

    public static MultipleOmicsPrideXMLParamExtractor getInstance() {

        if (MultipleOmicsPrideXMLParamExtractor.converter == null) {
//TODO solve this?            PropertyConfigurator.configure("src/main/resources/log4j.properties");
            MultipleOmicsPrideXMLParamExtractor.logger = Logger.getLogger(MultipleOmicsPrideXMLParamExtractor.class);
            MultipleOmicsPrideXMLParamExtractor.converter = new MultipleOmicsPrideXMLParamExtractor();
        }
        return converter;
    }

    public static void main(String[] args) {
        File testingFile = new File("C:\\Users\\Kenneth\\Documents\\NetBeansProjects\\respin\\target\\test-classes\\prideXML_repository\\PRIDE_Exp_Complete_Ac_8437.xml");
        //new File("V:\\PRIDE-DATA\\PRIDE-FTP-DOWNLOAD\\PRIDE_Exp_Complete_Ac_26901.xml");
        MultipleOmicsPrideXMLParamExtractor instance = new MultipleOmicsPrideXMLParamExtractor();
        instance.init(testingFile);
        try {
            instance.makeReport(new File("C:\\Users\\Kenneth\\Desktop\\example.txt"));
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        }
    }

    public void makeReport(File outputFile) throws FileNotFoundException {
        //setup streams to a file
        if (outputFile.exists()) {
            outputFile.delete();
        }
        out = new PrintWriter(new FileOutputStream(outputFile, true), true);
        getExperimentDetails();
        getExperimentInstrumentParameters();
        getExperimentDataProcessing();
        getExperimentAuthors();
        out.flush();
    }

    public void getExperimentDetails() {
        out.println("");
        out.println("---------------------------------------------------------");
        out.println("PRIDEXML \t " + reader.getExpAccession());
        out.println("---------------------------------------------------------");
        out.println("");
        //Title
        out.println("Title \t" + reader.getExpTitle());
        out.println("");
        out.println("---------------------------------------------------------");
        out.println("");
        //References
        List<Reference> references = reader.getReferences();
        for (Reference aRef : references) {
            out.println((references.indexOf(aRef) + 1) + ". \t  " + aRef.getRefLine());
        }
        out.println("");
        out.println("---------------------------------------------------------");
        out.println("");
        out.println("Protocol \t " + reader.getProtocol().getProtocolName());
        ProtocolSteps protocolSteps = reader.getProtocol().getProtocolSteps();
        for (Param aStepDesc : protocolSteps.getStepDescription()) {
            for (CvParam aCvParam : aStepDesc.getCvParam()) {
                out.println(aCvParam.getName() + " :  " + aCvParam.getValue());
            }
        }
        out.println("");
        out.println("---------------------------------------------------------");
        out.println("");
        out.println("Sample " + "\t  " + reader.getDescription().getAdmin().getSampleName());
        for (CvParam aCvParam : reader.getDescription().getAdmin().getSampleDescription().getCvParam()) {
            out.println(aCvParam.getCvLabel() + "\t " + aCvParam.getName());
        }
        out.println("");
        out.println("---------------------------------------------------------");
        out.println("");
    }

    public void getExperimentInstrumentParameters() {
        out.println("Instrument name" + " \t  " + reader.getInstrument().getInstrumentName());
        out.println("Instrument analyzer  \t  ");
        List<Param> analyzerList = reader.getInstrument().getAnalyzerList().getAnalyzer();
        for (Param anAnalyzer : analyzerList) {
            for (CvParam aCvParam : anAnalyzer.getCvParam()) {
                out.println(aCvParam.getCvLabel() + " \t " + aCvParam.getName());
            }
        }
        out.println("");
        out.println("Instrument detector  :  ");
        for (CvParam aDetector : reader.getInstrument().getDetector().getCvParam()) {
            out.println(aDetector.getCvLabel() + " \t " + aDetector.getName());
        }
        if (reader.getInstrument().getAdditional() != null) {
            out.println("Additional instrument details  :  ");
            for (CvParam anotherParam : reader.getInstrument().getAdditional().getCvParam()) {
                out.println(anotherParam.getCvLabel() + " \t " + anotherParam.getName());
            }
        }
        out.println("");
        out.println("---------------------------------------------------------");
        out.println("");
    }

    public void getExperimentDataProcessing() {
        /* Author Metadata	Name, organization, and other data about the author	Required	
         Contributor Metadata	Name, organization, and other data about the contributor	Recommended	
         */
        out.println("Instrument processing" + " \t  " + reader.getDataProcessing().getSoftware().getName() + "-version:" + reader.getDataProcessing().getSoftware().getVersion());
        if (reader.getDataProcessing().getProcessingMethod() != null) {
            for (CvParam aCvParam : reader.getDataProcessing().getProcessingMethod().getCvParam()) {
                out.println(aCvParam.getCvLabel() + " \t " + aCvParam.getName());
            }
        }
        out.println("");
        out.println("---------------------------------------------------------");
        out.println("");
    }

    public void getExperimentAuthors() {
        /* Author Metadata	Name, organization, and other data about the author	Required	
         Contributor Metadata	Name, organization, and other data about the contributor	Recommended	
         */
        out.println("Author info" + " :  ");
        List<Contact> contacts = reader.getAdmin().getContact();
        if (reader.getAdmin().getContact() != null) {
            for (Contact aContact : contacts) {
                out.println((contacts.indexOf(aContact) + 1) + ".");
                out.println("Name \t " + aContact.getName());
                out.println("Institution \t " + aContact.getInstitution());
                out.println("Contact info \t " + aContact.getContactInfo());
            }
        }
    }

    public static boolean isGZipped(File f) throws FileNotFoundException {
        RandomAccessFile raf = new RandomAccessFile(f, "r");

        long n = 0L;
        try {
            n = raf.readInt();
            raf.close();
        } catch (IOException ex) {
            logger.error(ex);
        } finally {
            if (raf != null) {
                raf = null;
            }
        }
        if (n != 0L) {
            //1f 8b = magic number !
            String nHex = Long.toHexString(n);
            nHex = nHex.substring(0, 4);
            if (nHex.equals("1f8b")) {
                logger.debug("Unzipping file...");
                return true;
            } else {
                logger.warn("This file is not a .gzip file");
                return false;
            }
        } else {
            return false;
        }
    }

    public static void setWorkingFile(File workingFile) {
        MultipleOmicsPrideXMLParamExtractor.tempFile = workingFile;
    }

    public void setBufferSize(int bufferSize) {
        gunZipper.setBufferSize(bufferSize);
    }

    public int getBufferSize() {
        return gunZipper.getBufferSize();
    }

    public void init(File prideXML) {

        try {
            gunZipper = GunZipper.getInstance();
            zipped = isGZipped(prideXML);
            logger.debug("Procedure for " + prideXML.getAbsolutePath().toString());
            logger.info("Starting conversion...");
            logger.setLevel(org.apache.log4j.Level.DEBUG);
            if (zipped) {
                //unzip method
                try {
                    String completeFileName = prideXML.getAbsolutePath().toString();
                    String[] unzippedFileNameArray = completeFileName.split("\\.xml");
                    prideXMLUnzipped = new File(unzippedFileNameArray[0] + ".xml");
                    tempFile = gunZipper.unzip(prideXML, prideXMLUnzipped);
                } catch (Exception ex) {
                    ex.printStackTrace();
                    logger.error("Could not unzip this file");
                }
            } else {
                tempFile = prideXML;
            }
            reader = new PrideXmlReader(tempFile);
        } catch (FileNotFoundException ex) {
            logger.error(ex);
        } finally {
            logger.setLevel(org.apache.log4j.Level.DEBUG);
            //TODO delete the temporary xml causes the reader to fail appearently : 
        }
    }

    public PrideXmlReader getPrideXmlReader() {
        return this.reader;
    }

    public boolean clearTempFiles() {
        boolean cleared = false;
        try {
            if (tempFile.exists() && zipped) {
                cleared = tempFile.delete();
                logger.debug("Cleared temporary files");
            }
        } catch (NullPointerException ex) {
            logger.debug("No temporary files were found");
        }
        return cleared;
    }
}
